package tasks;

import struct.enums.*;
import struct.InvServiceConfig;
import struct.SensorData;
import struct.SensorInfo;
import struct.State;
import struct.sync.SynchronousSensorData;
import lib4app.AbstractApp;
import lib4app.AppRemoteConnector;
import lib4app.InvCheck;
import lib4app.PlatformException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class TaskTwo extends AbstractApp {
    Map<String, SynchronousSensorData> checkResult = new HashMap<>();
    static boolean leftRecover = false;
    static ReentrantLock leftRecoverLock = new ReentrantLock();
    static boolean rightRecover = false;
    static ReentrantLock rightRecoverLock = new ReentrantLock();
    static boolean frontRecover = false;
    static ReentrantLock frontRecoverLock = new ReentrantLock();
    static double ySpeed = 0.0;
    static ReentrantLock ySpeedLock = new ReentrantLock();
    static double xSpeed = 0.0;
    static ReentrantLock xSpeedLock = new ReentrantLock();

    @Override
    public void configApp() {
        this.appName = "TaskTwo";
    }

    @Override
    public void getMsg(String sensorName, SensorData value) {
        if (value.getType() == SensorDataType.INV_REPORT) {
            checkResult.computeIfAbsent(sensorName, k -> new SynchronousSensorData()).put(value);
        }
    }
    public void test(){
        try {
            TaskTwo app = new TaskTwo();
            AppRemoteConnector connector = AppRemoteConnector.getInstance();
            connector.connectPlatform("127.0.0.1", 9090);
            connector.registerApp(app);
            InvServiceConfig config = new InvServiceConfig();
            config.setGrpOn(false);
            config.setInvGenThro(50);
            config.setChkFiles(List.of("demo/invariant/tasks/TaskTwo.java"));
            connector.serviceStart(ServiceType.INV, config);
            InvCheck checker = InvCheck.getInstance();
            connector.getMsgThread(CmdType.START);
            Map<String, SensorInfo> supportedSensors = connector.getSupportedSensors();
            if (supportedSensors.containsKey("MockCar") && supportedSensors.get("MockCar").state == State.ON) {
                connector.registerSensor("MockCar", SensorMode.ACTIVE, -1);
                connector.getSensorData("MockCar");
            }
            boolean b = checker.loadFrom("../config/TaskTwo.json");
            long testTime = 600 * 1000; // 600 * 1000
            long startTime = System.currentTimeMillis();
            double crashDisThro = 10.0;
            do {
                try {
                    Thread.sleep(50);
                } catch (Exception ignored) {
                }
                // 获得传感器数据
                SensorData distance = connector.getSensorData("MockCar");
                double left = (Integer)  distance.getData("left");
                double right = (Integer) distance.getData("right");
                double front = (Integer) distance.getData("front");
                // 检查不变式，下一步做出什么action
                checker.check(left);
                checker.check(right);
                checker.check(front);

                CheckResult leftCheck = checker.getResult(app.checkResult.computeIfAbsent("INV_REPORT97", k -> new SynchronousSensorData()).blockTake());
                if (leftCheck == CheckResult.INV_GENERATING) {
                    leftRecoverLock.lock();
                    leftRecover = false;
                    leftRecoverLock.unlock();
                }else if (leftCheck == CheckResult.INV_PASSED)  {
                    leftRecoverLock.lock();
                    leftRecover = false;
                    leftRecoverLock.unlock();
                } else {
                    leftRecoverLock.lock();
                    ySpeedLock.lock();
                    leftRecover = true;
                    ySpeed = 2 * TaskOneKeyListener.zs;
                    ySpeedLock.unlock();
                    leftRecoverLock.unlock();
//                    continue; // 左右两侧不可能同时违反不变式
                }

                CheckResult rightCheck = checker.getResult(app.checkResult.computeIfAbsent("INV_REPORT98", k -> new SynchronousSensorData()).blockTake());
                if (rightCheck == CheckResult.INV_GENERATING) {
                    rightRecoverLock.lock();
                    rightRecover = false;
                    rightRecoverLock.unlock();
                }else if (rightCheck == CheckResult.INV_PASSED)  {
                    rightRecoverLock.lock();
                    rightRecover = false;
                    rightRecoverLock.unlock();
                } else {
                    rightRecoverLock.lock();
                    ySpeedLock.lock();
                    rightRecover = true;
                    ySpeed = -2 * TaskOneKeyListener.zs;
                    ySpeedLock.unlock();
                    rightRecoverLock.unlock();
                }

                CheckResult frontCheck = checker.getResult(app.checkResult.computeIfAbsent("INV_REPORT99", k -> new SynchronousSensorData()).blockTake());
                if (frontCheck == CheckResult.INV_GENERATING) {
                    frontRecoverLock.lock();
                    frontRecover = false;
                    frontRecoverLock.unlock();
                }else if (frontCheck == CheckResult.INV_PASSED)  {
                    rightRecoverLock.lock();
                    rightRecover = false;
                    rightRecoverLock.unlock();
                } else {
                    frontRecoverLock.lock();
                    xSpeedLock.lock();
                    rightRecover = true;
                    xSpeed = 2 * TaskOneKeyListener.xys;
                    xSpeedLock.unlock();
                    frontRecoverLock.unlock();
                }
//                if(leftCheck != CheckResult.INV_GENERATING && rightCheck != CheckResult.INV_GENERATING && frontCheck != CheckResult.INV_GENERATING){
//                    checker.saveTo("Resources/app.TaskTwo.json");
//                    break;
//                }
//                System.out.println(checker.checkGenerated());

            } while (System.currentTimeMillis() - startTime < testTime);

            connector.unregisterApp(app);
            connector.disConnectPlatform();
        } catch (PlatformException e) {
            System.out.println("远程平台连接异常，请重启应用以尝试重新连接远程平台！");
        }catch (Exception e){
            System.out.println("数据发送完毕，本次测试结束！");
            System.exit(1);
        }
    }


    public static void main(String[] args) throws InterruptedException {
        TaskTwo app = new TaskTwo();
        app.test();
    }
}
